<!doctype html><html lang=cn-zh><head><meta charset=UTF-8><meta name=viewport content="width=device-width,initial-scale=1"><meta http-equiv=X-UA-Compatible content="IE=edge"><style type=text/css>body{font-family:monospace}</style><title>[python]web框架中的代码自动重载怎么实现</title>
<meta name=description content="A blog maintained by Vimiix."><link rel=stylesheet href=/css/style.css><script>var _hmt=_hmt||[];(function(){var e,t=document.createElement("script");t.src="https://hm.baidu.com/hm.js?7c24231917964240bae97e813810620c",e=document.getElementsByTagName("script")[0],e.parentNode.insertBefore(t,e)})()</script></head><body><header>====================<br>== Hi, I'm Vimiix ==<br>====================<div style=float:right;color:gray;font-size:x-large>Get hands dirty.</div><br><p><nav><a href=https://www.vimiix.com/><b>首页</b></a>.
<a href=/posts/><b>文章列表</b></a>.
<a href=/projects/><b>开源项目</b></a>.
<a href=/tags/><b>标签</b></a>.
<a href=/friends/><b>友链</b></a>.
<a href=/about/><b>关于我</b></a>.
<a href=/index.xml><b>RSS</b></a>.</nav></p></header><main><article><h1>[python]web框架中的代码自动重载怎么实现</h1><b><time>2018.01.08 22:37</time></b>
<a href=/tags/python>Python</a>
<a href=/tags/reload>reload</a>
<a href=/tags/flask>Flask</a>
<a href=/tags/django>Django</a>
<a href=/tags/uwsgi>uWSGI</a><div><p>在开发和调试 wsgi 应用程序时，有很多方法可以自动重新加载代码。例如，如果你使用的是<code>werkzeug</code>，则只需要传<code>use_reloader</code>参数即可：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span>run_sumple(<span style=color:#e6db74>&#39;127.0.0.1&#39;</span>, <span style=color:#ae81ff>5000</span>, app, use_reloader<span style=color:#f92672>=</span><span style=color:#66d9ef>True</span>)
</span></span></code></pre></div><p>对于 Flask,实际上在内部使用 werkzeug，所以你需要设置 debug = true：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span>app<span style=color:#f92672>.</span>run(debug<span style=color:#f92672>=</span><span style=color:#66d9ef>True</span>)
</span></span></code></pre></div><p>django 会在你修改任何代码的时候自动为你重新加载：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span>python manage<span style=color:#f92672>.</span>py runserver
</span></span></code></pre></div><p>所有这些例子在本地开发的时候都非常有用，但是，建议不要在实际生产中使用。</p><p>作为学习，可以一起来看一下，python 是如何让代码自动地重新加载的？</p><h2 id=uwsgi>uWSGI</h2><p>如果使用的是 <code>uwsgi</code> 和 <code>django</code> ，实际上可以直接通过代码跳转查看一下 <code>django</code> 本身的自动重载机制：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>import</span> uwsgi
</span></span><span style=display:flex><span><span style=color:#f92672>from</span> uwsgidecorators <span style=color:#f92672>import</span> timer
</span></span><span style=display:flex><span><span style=color:#f92672>from</span> django.utils <span style=color:#f92672>import</span> autoreload
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@timer</span>(<span style=color:#ae81ff>3</span>)
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>change_code_gracefull_reload</span>(sig):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>if</span> autoreload<span style=color:#f92672>.</span>code_changed():
</span></span><span style=display:flex><span>        uwsgi<span style=color:#f92672>.</span>reload()
</span></span></code></pre></div><p>可以看出，<code>django</code> 通过一个定时器在不断的监测代码是否有变化，以此来出发重新加载函数。</p><p>如果你使用的是其他框架，或者根本没有框架，那么可能就需要在应用程序中自己来实现代码改动监测。这里是一个很好的示例代码，借用和修改自 <a href=http://cherrypy.org/>cherrypy</a>：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>import</span> os<span style=color:#f92672>,</span> sys
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>_mtimes <span style=color:#f92672>=</span> {}
</span></span><span style=display:flex><span>_win <span style=color:#f92672>=</span> (sys<span style=color:#f92672>.</span>platform <span style=color:#f92672>==</span> <span style=color:#e6db74>&#34;win32&#34;</span>)
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>_error_files <span style=color:#f92672>=</span> []
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>code_changed</span>():
</span></span><span style=display:flex><span>    filenames <span style=color:#f92672>=</span> []
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>for</span> m <span style=color:#f92672>in</span> sys<span style=color:#f92672>.</span>modules<span style=color:#f92672>.</span>values():
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>try</span>:
</span></span><span style=display:flex><span>            filenames<span style=color:#f92672>.</span>append(m<span style=color:#f92672>.</span>__file__)
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>except</span> <span style=color:#a6e22e>AttributeError</span>:
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>pass</span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>for</span> filename <span style=color:#f92672>in</span> filenames <span style=color:#f92672>+</span> _error_files:
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> <span style=color:#f92672>not</span> filename:
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>continue</span>
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> filename<span style=color:#f92672>.</span>endswith(<span style=color:#e6db74>&#34;.pyc&#34;</span>) <span style=color:#f92672>or</span> filename<span style=color:#f92672>.</span>endswith(<span style=color:#e6db74>&#34;.pyo&#34;</span>):
</span></span><span style=display:flex><span>            filename <span style=color:#f92672>=</span> filename[:<span style=color:#f92672>-</span><span style=color:#ae81ff>1</span>]
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> filename<span style=color:#f92672>.</span>endswith(<span style=color:#e6db74>&#34;$py.class&#34;</span>):
</span></span><span style=display:flex><span>            filename <span style=color:#f92672>=</span> filename[:<span style=color:#f92672>-</span><span style=color:#ae81ff>9</span>] <span style=color:#f92672>+</span> <span style=color:#e6db74>&#34;.py&#34;</span>
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> <span style=color:#f92672>not</span> os<span style=color:#f92672>.</span>path<span style=color:#f92672>.</span>exists(filename):
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>continue</span> <span style=color:#75715e># File might be in an egg, so it can&#39;t be reloaded.</span>
</span></span><span style=display:flex><span>        stat <span style=color:#f92672>=</span> os<span style=color:#f92672>.</span>stat(filename)
</span></span><span style=display:flex><span>        mtime <span style=color:#f92672>=</span> stat<span style=color:#f92672>.</span>st_mtime
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> _win:
</span></span><span style=display:flex><span>            mtime <span style=color:#f92672>-=</span> stat<span style=color:#f92672>.</span>st_ctime
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> filename <span style=color:#f92672>not</span> <span style=color:#f92672>in</span> _mtimes:
</span></span><span style=display:flex><span>            _mtimes[filename] <span style=color:#f92672>=</span> mtime
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>continue</span>
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> mtime <span style=color:#f92672>!=</span> _mtimes[filename]:
</span></span><span style=display:flex><span>            _mtimes<span style=color:#f92672>.</span>clear()
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>try</span>:
</span></span><span style=display:flex><span>                <span style=color:#66d9ef>del</span> _error_files[_error_files<span style=color:#f92672>.</span>index(filename)]
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>except</span> <span style=color:#a6e22e>ValueError</span>:
</span></span><span style=display:flex><span>                <span style=color:#66d9ef>pass</span>
</span></span><span style=display:flex><span>            <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>return</span> <span style=color:#66d9ef>False</span>
</span></span></code></pre></div><p>你可以将上面的内容保存在你的项目中的 <code>autoreload.py</code> 中，然后我们就可以像下面这样去调用它（类似于 <code>django</code> 的例子）：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>import</span> uwsgi
</span></span><span style=display:flex><span><span style=color:#f92672>from</span> uwsgidecorators <span style=color:#f92672>import</span> timer
</span></span><span style=display:flex><span><span style=color:#f92672>import</span> autoreload
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@timer</span>(<span style=color:#ae81ff>3</span>)
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>change_code_gracefull_reload</span>(sig):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>if</span> autoreload<span style=color:#f92672>.</span>code_changed():
</span></span><span style=display:flex><span>        uwsgi<span style=color:#f92672>.</span>reload()
</span></span></code></pre></div><h2 id=gunicorn>gunicorn</h2><p>对于 <code>gunicorn</code> ，我们需要写一个脚本来 <code>hook（钩子:触发）</code> 到 <code>gunicorn</code> 的配置中：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>import</span> threading
</span></span><span style=display:flex><span><span style=color:#f92672>import</span> time
</span></span><span style=display:flex><span><span style=color:#66d9ef>try</span>:
</span></span><span style=display:flex><span>    <span style=color:#f92672>from</span> django.utils <span style=color:#f92672>import</span> autoreload
</span></span><span style=display:flex><span><span style=color:#66d9ef>except</span> <span style=color:#a6e22e>ImportError</span>:
</span></span><span style=display:flex><span>    <span style=color:#f92672>import</span> autoreload
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>reloader</span>(server):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>while</span> <span style=color:#66d9ef>True</span>:
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>if</span> autoreload<span style=color:#f92672>.</span>code_changed():
</span></span><span style=display:flex><span>            server<span style=color:#f92672>.</span>reload()
</span></span><span style=display:flex><span>        time<span style=color:#f92672>.</span>sleep(<span style=color:#ae81ff>3</span>)
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>when_ready</span>(server):
</span></span><span style=display:flex><span>    t <span style=color:#f92672>=</span> threading<span style=color:#f92672>.</span>Thread(target<span style=color:#f92672>=</span>reloader, args<span style=color:#f92672>=</span>(server, ))
</span></span><span style=display:flex><span>    t<span style=color:#f92672>.</span>daemon <span style=color:#f92672>=</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>    t<span style=color:#f92672>.</span>start()
</span></span></code></pre></div><p>你需要把上面的代码保存到一个文件中，比如说 <code>config.py</code> ，然后像下面这样传给 <code>gunicorn</code> ：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>gunicorn -c config.py application
</span></span></code></pre></div><h2 id=外部解决方法>外部解决方法</h2><p>你也可以通过正在使用的 <code>wsgi</code> 服务系统本身以外的一些方法来实现重启系统，它只需发出一个信号，告诉系统重启代码，比如可以使用 <a href=https://github.com/gorakhargosh/watchdog>watchdog</a>。例如：</p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>watchmedo shell-command --patterns<span style=color:#f92672>=</span><span style=color:#e6db74>&#34;*.py&#34;</span> --recursive --command<span style=color:#f92672>=</span><span style=color:#e6db74>&#39;kill -HUP `cat /tmp/gunicorn.pid`&#39;</span> /path/to/project/
</span></span></code></pre></div><blockquote><p>转载请保留以下信息：</p><p>原文链接： <a href=http://www.vimiix.com/post/2018/01/08/autoreload-code-in-python/>http://www.vimiix.com/post/2018/01/08/autoreload-code-in-python/</a></p></blockquote></div></article></main><aside><div><div><h3>LATEST POSTS</h3></div><div><ul><li><a href=/posts/2025-10-16-kubernetes-apiserver-authorization-mechanism/>Kubernetes APIServer 鉴权机制</a></li><li><a href=/posts/2025-09-30-kubernetes-apiserver-authentication-mechanism/>Kubernetes APIServer 认证机制</a></li><li><a href=/posts/2024-12-16-deploy-kubernetes-by-kubeadm/>使用 kubeadm 搭建 kubernetes 集群</a></li><li><a href=/posts/2024-09-20-how-to-code-review/>如何做code review</a></li><li><a href=/posts/2024-08-12-weakref-in-python/>Python中的弱引用</a></li></ul></div></div></aside><footer><p>Social Links:
<a href=https://github.com/vimiix><b>Github</b></a>.
<a href=https://www.douban.com/people/vimiix/><b>Douban</b></a>.
<a href=mailto:i@vimiix.com><b>Email</b></a>.<br><hr>&copy; 2017-2025
Vimiix Yao; All rights reserved.
<a href=https://beian.miit.gov.cn/>京ICP备19015214号-1</a></p><script src=https://l2dwidget.js.org/lib/L2Dwidget.min.js></script><script>L2Dwidget.init({model:{jsonPath:"https://unpkg.com/live2d-widget-model-tororo@1.0.5/assets/tororo.model.json"}})</script></footer></body></html>